﻿//-----------------------------------------------------------------------
// <copyright file="CategoryListView.cs" company="Forebrain Technology, LLC">
//
// Copyright (c) Forebrain Technology, LLC. All rights reserved.
// 
// This source code is released under the Microsoft Public License (Ms-PL).
//
// </copyright>
//-----------------------------------------------------------------------
namespace PivotCollectionMaker.WinFormApplication.Controls
{
    using System;
    using System.ComponentModel;
    using System.Windows.Forms;
    using PivotCollectionTools.Data;

    /// <summary>
    /// List of action.
    /// </summary>
    public enum ListViewAction 
    {
        /// <summary>
        /// Add a recrod.
        /// </summary>
        Add,

        /// <summary>
        /// Delete a record.
        /// </summary>
        Delete,

        /// <summary>
        /// Update a record.
        /// </summary>
        Update,

        /// <summary>
        /// Rename the record.
        /// </summary>
        Rename
    }

    /// <summary>
    /// Windows form implementation of the Category List view
    /// </summary>
    public partial class CategoryListView : UserControl, ICategoryListView
    {
        /// <summary>
        /// Storage for the presenter this view will use.
        /// </summary>
        private CategoryListPresenter presenter;

        /// <summary>
        /// Initializes a new instance of the <see cref="CategoryListView"/> class.
        /// </summary>
        /// <param name="table">The table to retrieve the scema.</param>
        public CategoryListView(PivotTable table)
        {
            InitializeComponent();

            this.presenter = new CategoryListPresenter(this, table);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CategoryListView"/> class.
        /// </summary>
        public CategoryListView()
            : this(new PivotTable())
        {
        }

        /// <summary>
        /// Occurs when schema changed.
        /// </summary>
        public event EventHandler SchemaChanged;

        /// <summary>
        /// Occurs when a column added].
        /// </summary>
        public event EventHandler<ColumnListViewEventArgs> ColumnAdded;

        /// <summary>
        /// Occurs before a column is deleted.
        /// </summary>
        public event EventHandler<ColumnListViewEventArgs> BeforeColumnDeleted;

        /// <summary>
        /// Occurs when a column is deleted.
        /// </summary>
        public event EventHandler<ColumnListViewEventArgs> ColumnDeleted;

        /// <summary>
        /// Occurs before a category is deleted.
        /// </summary>
        public event EventHandler<CategoryListViewEventArgs> BeforeCategoryDeleted;

        /// <summary>
        /// Occurs when a category is deleted.
        /// </summary>
        public event EventHandler CategoryDeleted;

        /// <summary>
        /// Occurs when a category item selected.
        /// </summary>
        public event EventHandler CategoryItemSelected;

        /// <summary>
        /// Gets the index of the selected category.
        /// </summary>
        /// <value>The index of the selected category.</value>
        [Browsable(false)]
        public int SelectedCategoryIndex { get; private set; }

        /// <summary>
        /// Gets the index of the selected column.
        /// </summary>
        /// <value>The index of the selected column.</value>
        public int SelectedColumnIndex
        {
            get
            {
                return this.uxColumnListBox.SelectedIndex;
            }
        }

        /// <summary>
        /// Gets the item count.
        /// </summary>
        /// <value>The item count of the category list view.</value>
        [Browsable(false)]
        public int ItemCount
        {
            get { return this.uxCetegoryListBox.Items.Count; }
        }

        /// <summary>
        /// Gets the selected category.
        /// </summary>
        /// <value>The selected category of the category list view.</value>
        [Browsable(false)]
        public PivotTableCategory SelectedCategory
        {
            get
            {
                if (this.presenter.Model.Categories.Count == 0)
                {
                    return null;
                }

                return this.SelectedCategoryIndex != -1 ? this.presenter.Model.Categories[this.SelectedCategoryIndex] : null;
            }
        }

        /// <summary>
        /// Gets the selected column.
        /// </summary>
        /// <value>The selected column in the category list view.</value>
        public string SelectedColumn
        {
            get
            {
                return this.SelectedCategoryIndex != -1 ? this.uxColumnListBox.Items[this.SelectedColumnIndex].ToString() : string.Empty;
            }
        }

        /// <summary>
        /// Shows the category property.
        /// </summary>
        /// <param name="category">The category.</param>
        public void ShowCategoryProperty(PropertyBag category)
        {
            this.uxCategoryProperties.SelectedObject = category;
        }

        /// <summary>
        /// Adds the specified item to the category list.
        /// </summary>
        /// <param name="item">The specified item to add to the category list.</param>
        public void AddCategoryListItem(string item)
        {
            this.uxCetegoryListBox.Items.Add(item);
        }

        /// <summary>
        /// Sets the view model.
        /// </summary>
        /// <param name="table">The table.</param>
        public void SetViewModel(PivotTable table)
        {
            this.presenter.Model = table;
        }

        /// <summary>
        /// Removes the category.
        /// </summary>
        /// <param name="index">The index.</param>
        public void RemoveCategory(int index)
        {
            this.uxCetegoryListBox.Items.RemoveAt(index);
        }

        /// <summary>
        /// Clears the category list.
        /// </summary>
        public void ClearCategoryList()
        {
            this.uxCetegoryListBox.Items.Clear();
        }

        /// <summary>
        /// Clears the column list.
        /// </summary>
        public void ClearColumnList()
        {
            this.uxColumnListBox.Items.Clear();
        }

        /// <summary>
        /// Clears this instance.
        /// </summary>
        public void Clear()
        {
            this.SelectedCategoryIndex = -1;

            this.uxCetegoryListBox.Items.Clear();
            this.uxColumnListBox.Items.Clear();

            this.presenter.Clear();
            this.uxCategoryProperties.SelectedObject = null;
        }

        /// <summary>
        /// Adds the column list item.
        /// </summary>
        /// <param name="column">The column.</param>
        public void AddColumnListItem(string column)
        {
            this.uxColumnListBox.SelectedIndex = this.uxColumnListBox.Items.Add(column);
        }

        /// <summary>
        /// Shows the message.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="caption">The caption.</param>
        public void ShowMessage(string message, string caption)
        {
            MessageBox.Show(message, caption, MessageBoxButtons.OK);
        }

        /// <summary>
        /// Raises the <see cref="E:BeforeCategoryDeleted"/> event.
        /// </summary>
        /// <param name="e">The <see cref="PivotCollectionMaker.WinFormApplication.Controls.CategoryListViewEventArgs"/> instance containing the event data.</param>
        protected virtual void OnBeforeCategoryDeleted(CategoryListViewEventArgs e)
        {
            if (this.BeforeCategoryDeleted != null)
            {
                this.BeforeCategoryDeleted(this, e);
            }
        }

        /// <summary>
        /// Called when category deleted.
        /// </summary>
        protected virtual void OnCategoryDeleted()
        {
            if (this.CategoryDeleted != null)
            {
                this.CategoryDeleted(this, new EventArgs());
            }
        }

        /// <summary>
        /// Raises the <see cref="E:ColumnDeleted"/> event.
        /// </summary>
        /// <param name="e">The <see cref="PivotCollectionMaker.WinFormApplication.Controls.ColumnListViewEventArgs"/> instance containing the event data.</param>
        protected virtual void OnColumnDeleted(ColumnListViewEventArgs e)
        {
            if (this.ColumnDeleted != null)
            {
                this.ColumnDeleted(this, e);
            }
        }

        /// <summary>
        /// Raises the <see cref="E:ColunnAdded"/> event.
        /// </summary>
        /// <param name="e">The <see cref="PivotCollectionMaker.WinFormApplication.Controls.ColumnListViewEventArgs"/> instance containing the event data.</param>
        protected virtual void OnColunnAdded(ColumnListViewEventArgs e)
        {
            if (this.ColumnAdded != null)
            {
                this.ColumnAdded(this, e);
            }
        }

        /// <summary>
        /// Raises the <see cref="E:BeforeColumnDeleted"/> event.
        /// </summary>
        /// <param name="e">The <see cref="PivotCollectionMaker.WinFormApplication.Controls.ColumnListViewEventArgs"/> instance containing the event data.</param>
        protected virtual void OnBeforeColumnDeleted(ColumnListViewEventArgs e)
        {
            // Test if there are any even handlers for before a column is deleted.
            if (this.BeforeColumnDeleted != null)
            {
                // Call the event hadler passing the event arguments specifying the column
                // to be deleted.
                this.BeforeColumnDeleted(this, e);
            }
        }

        /// <summary>
        /// Called when schema changed.
        /// </summary>
        protected virtual void OnSchemaChanged()
        {
            // Test if there are any even handlers for when the schema changed.
            if (this.SchemaChanged != null)
            {
                // Call the event handler.
                this.SchemaChanged(this, new EventArgs());
            }
        }

        /// <summary>
        /// Called when category item selected.
        /// </summary>
        protected virtual void OnCategoryItemSelected()
        {
            // Test if there are any even handlers for when a category item is selected.
            if (this.CategoryItemSelected != null)
            {
                // Call into the event handlers.
                this.CategoryItemSelected(this, new EventArgs());
            }
        }

        /// <summary>
        /// Handles the Click event of the uxAddCategoryButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void AddCategoryButton_Click(object sender, EventArgs e)
        {
            // Create a Category Form with the defaults for a new column.
            var addForm = new PivotTableCategoryForm()
            {
                Model = new PivotTableCategory("New Category", PivotTableCellType.Text)
            };

            // If the user selected OK then proceed with adding.
            if (addForm.ShowDialog() == DialogResult.OK)
            {
                // Call into the presenter to add the Cateogry entered on the form.
                this.presenter.AddCategory(addForm.Model);
            }
        }

        /// <summary>
        /// Handles the Click event of the uxRemoveCategoryButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void RemoveCategoryButton_Click(object sender, EventArgs e)
        {
            // Build the arguments for the Category to be deleted.
            var arguments = new CategoryListViewEventArgs(this.SelectedCategory, ListViewAction.Delete);

            // Notify any event handlers before the category is deleted.
            this.OnBeforeCategoryDeleted(arguments);
                        
            // If an event handler changes the continue flag to false then don't continue.
            if (!arguments.Continue)
            {
                return;
            }

            // Call into the presenter to delete the category.
            this.presenter.DeleteCategory();

            // Notify any event handler that the category was deleted.
            this.OnCategoryDeleted();
            
            // Notify any event handler that the Pivot Table schema changed.
            this.OnSchemaChanged();
        }

        /// <summary>
        /// Handles the SelectedIndexChanged event of the uxCategoryListBox control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void CategoryListBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            // Maker sure the selected index is valid. Otherwise don't change.
            if (this.uxCetegoryListBox.SelectedIndex >= 0)
            {
                this.SelectedCategoryIndex = this.uxCetegoryListBox.SelectedIndex;
            }
            
            // Refresh the properties for the category.
            this.uxCategoryProperties.Refresh();
            
            // Notify any event handlers that a category item was selected.
            this.OnCategoryItemSelected();
        }

        /// <summary>
        /// Handles the Click event of the uxAddColumnButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void AddColumnButton_Click(object sender, EventArgs e)
        {
            // Call to the presenter to add a new column.
            var newColumn = this.presenter.AddColumn();
            
            // Notify any event handlers that a Column was added.
            this.OnColunnAdded(new ColumnListViewEventArgs(newColumn, ListViewAction.Add));

            // Notify any event handlers that the Pivot Table Schema changed.
            this.OnSchemaChanged();
        }

        /// <summary>
        /// Handles the Click event of the uxDeleteColumnButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void DeleteColumnButton_Click(object sender, EventArgs e)
        {
            // Build the arguments based on the selected column.
            var arguments = new ColumnListViewEventArgs(this.presenter.Model.Columns[this.SelectedColumn], ListViewAction.Delete);

            // Notify any event handlers before the column is deleted.
            this.OnBeforeColumnDeleted(arguments);

            // If an event handler changes the continue flag to false then don't continue.
            if (!arguments.Continue)
            {
                return;
            }

            // Call to the presenter to delete the column.
            this.presenter.DeleteColumn();

            // Notify any event handlers that the Column was Deleted.
            this.OnColumnDeleted(arguments);

            // Notify any event handlers that the Schema Changed.
            this.OnSchemaChanged();
        }
    }
}
